"""
Frame for choose a polynomial.
"""

import tkinter as tk
import tkinter.messagebox as messagebox
from ui.PolynomialConversion import *

class CrcPolynomialChoiceFrame(tk.Frame):
    """This frame contains the inputs for the poynom choice."""
    def create_standard_polynoms(self):
        """Create standard polynomial."""
        self.userInputStringValue = "User-entered polynomial"
        self.polynoms = {
            self.userInputStringValue:'',
            "Parity bit":0b11,
            "CRC-4-ITU":0b10011,
            "Avis v41":0b10001000000100001,
            "Avis v40":0b100000001,
            }
        self.defaultPolynom = "CRC-4-ITU"
    def create_tk_vars(self):
        """Create the variables for all the widgets in the frame."""
        self.polynomListCur = tk.StringVar(self)
        self.polynomialCorrect = tk.BooleanVar(self)
        self.polynomialCorrect.set(False)
        
    def create_polynomial_choice_info(self):
        """Create the message widget."""
        messageText = "Please choose a polynomial."
        self.description = tk.Message(self)
        self.description["width"] = "250" # pixels
        self.description["text"] = messageText
        self.description["anchor"] = "w"
        self.description.grid(
            column=0,row=0,columnspan=2,sticky=tk.N+tk.S+tk.E+tk.W,pady=5)
    
    def create_currentPolynomField(self):
        """Create the text widget for the input."""
        self.polynomEditField = tk.Text(self)
        self.polynomEditField["width"] = "20" # columns
        self.polynomEditField["height"] = "1" # lines
        self.polynomEditField["wrap"] = "none"
        self.enableModifCb = True # Hack for the modification callback.
        def cb(*args):
            if self.enableModifCb:
                self.enableModifCb = False
                self.polynomListCur.set(self.userInputStringValue)
                self.polynomialCorrect.set(self.polynomial_is_correct())
                self.update_polynomial_correctness()
                self.polynomEditField.edit_modified(False)
                self.enableModifCb = True
        self.polynomEditField.bind("<<Modified>>",cb)
        self.polynomEditField.grid(
            column=0,row=2,sticky=tk.N+tk.S+tk.E+tk.W,padx=5,pady=5)

    def create_polynom_correctness_indicator(self):
        """Create the message widget to indicate to the user
        if the polynom is correct or not."""
        self.textPolynomCorrect = "Polynomial correct"
        self.textPolynomIncorrect = "Can't understand"
        self.polynomialCorrectLabel = tk.Message(self)
        self.polynomialCorrectLabel["width"] = "100" # pixels
        self.polynomialCorrectLabel["anchor"] = "w"
        self.polynomialCorrectLabel["text"] = self.textPolynomCorrect
        self.polynomialCorrectLabel.grid(
            column=1,row=2,sticky=tk.N+tk.S+tk.E+tk.W)
    
    def create_std_crc_list(self):
        """Create a small list to allow the user to select
        a default polynomial or enter a custom one."""
        self.polynomListCur.set(self.defaultPolynom)
        # The reverse solves an ordering problem.
        self.standardCrcsList = tk.OptionMenu(
            self,self.polynomListCur,*(reversed(list(self.polynoms))))
        self.standardCrcsList.grid(column=0,row=1,sticky=tk.W,padx=5,pady=5)

    def create_help_button(self):
        """Create the help button."""
        def display_help():
            text = """Here, you can define the polynomial you want to use.

The combo-box allows you to choose between some standards polynomials.
You may also write your own polynomials.
The syntax is quite permissive, and two formats are understood :
- The binary input : 10011 for example, standing for x**4+x**1+1
- The text input : x**2+1 for example. This is equivalent to :
    - x2+1
    - x^2+1
    - x*2+1
    - x^^2+1
Note that a polynomial must be of a degree higher than 0, and
that the x**0 (or 1) is mandatory to be usable for a CRC calculation.

See the "What is CRC?" entry in the help menu for more informations."""
            messagebox.showinfo('Help', text)
        self.help_button = tk.Button(self, text='?', command=display_help)
        self.help_button.place(in_=self,anchor=tk.N+tk.E,relx=1,x=-5,y=5)
    
    def create_widgets(self):
        """Create the frame starting layout."""
        self.create_polynomial_choice_info()
        self.create_std_crc_list()
        self.create_currentPolynomField()
        self.create_polynom_correctness_indicator()
        self.create_help_button()
        def updatePolynom(name=None,index=None,mode=None):
            self.polynomListCur.set(self.polynomListCur.get())
            polynom = self.polynoms[self.polynomListCur.get()]
            if polynom != "":
                toWrite = bin(self.polynoms[self.polynomListCur.get()])
                toWrite = toWrite[2:] # Removing the 0b.
                self.enableModifCb = False
                self.polynomEditField.delete(1.0, tk.END)
                self.polynomEditField.insert(tk.INSERT,toWrite)
                self.polynomEditField.edit_modified(False)
                self.enableModifCb = True
            self.update_polynomial_correctness()
        updatePolynom()
        self.polynomListCur.trace_variable("w",updatePolynom)
    def create_grid(self):
        """Create the grid with default weight."""
        
    def __init__(self,master=None):
        tk.Frame.__init__(self, master)
        self.grid_propagate(0) # Disables geometry propagation.
        self["width"] = "300"
        self["height"] = "115"
        self["relief"] = "sunken"
        self["borderwidth"] = "2"
        self.create_tk_vars()
        self.create_standard_polynoms()
        self.create_widgets()
    def polynomial_is_correct(self):
        """Indicate whether the polynomial is correct or not."""
        return self.get_polynomial() is not None

    def update_polynomial_correctness(self):
        """Update a lablel with some text if the polynomial is understood,
        or another string otherwise."""
        if self.polynomial_is_correct():
            self.polynomialCorrectLabel["text"] = self.textPolynomCorrect
            self.polynomEditField['bg'] = '#ffffff'
            self.polynomEditField['fg'] = '#000000'
        else:
            self.polynomialCorrectLabel["text"] = self.textPolynomIncorrect
            self.polynomEditField['bg'] = '#ee0011'
            self.polynomEditField['fg'] = '#ffffff'

    
    def get_polynomial(self):
        """Returns the user inputed polynomial.

        If the data is not currently a polynomial,returns None."""
        data = self.polynomEditField.get(1.0,tk.END)
        try: # Trying a binary string.
            ret = int(data,2)
        except:
            # Not a problem, let's try it another way.
            ret = get_text_polynomial_as_binary_string(data)
        if ret is None:
            return None
        if ret < 2: # It has no sense to make one under 2.
            return None
        if not ret % 2: # To be a CRC, the polynom must have a x0 coeff.
            return None
        return ret

    def get_polynomial_length(self):
        p = self.get_polynomial()
        if p == None:
            return None
        else:
            return len(bin(p)[2:])-1
